package au.id.wattle.chapman.j2as3;

import java.util.ArrayList;
import java.util.HashMap;

public class Converter {

	private String str;
	private String orginalStr;
	private Tokenizer tokenizer;
	private boolean inFNDef;
	private boolean inConstructor;
	private String cFNName;
	private String cFNType;
	private String post;
	private boolean isInnerClass = false;
	private ArrayList<Integer> posInnerClass = new ArrayList<Integer>();
	private HashMap<String, String> packageImports = new HashMap<String, String>();
	public int classCount;
	public int lineCount;
	public boolean isJavaFile;
	private boolean hasBeenAddedExclamationPoint = false;

	public Converter(String str) {
		orginalStr = this.str = str;
		tokenizer = new Tokenizer(str);
		lineCount = classCount = 0;
		isJavaFile = false;
	}

	public String getNewClass() {
		ArrayList<Token> tokens = tokenizer.getAllTokens();
		String str = "";
		String orig = this.str;
		String temp;
		int lastPos = 0;
		int newPos;
		boolean used;
		Token t;

		post = "";

		for (int i = 0; i < tokens.size(); i++) {
			t = tokens.get(i);

			if (t.getString().equals("import")) {
				String imp = t.getString() + " "
						+ tokens.get(i + 1).getString()
						+ tokens.get(i + 2).getString();
				String s = tokens.get(i + 1).getString();
				int endPoint = s.lastIndexOf(".");
				String nameImpClass = s.substring(endPoint + 1, s.length());

				packageImports.put(nameImpClass, imp);
			}
			used = false;
			if (i < tokens.size() - 3) {
				if (isIdentifier(tokens.get(i))
						&& tokens.get(i + 1).getType() == Token.STRING_LITERAL
						&& (tokens.get(i + 2).getString().equals("=")
								|| tokens.get(i + 2).getString().equals(";")
								|| tokens.get(i + 2).getString().equals(",") || tokens
								.get(i + 2).equals(")"))) {
					String varName = tokens.get(i + 1).toString();
					String varType = toASType(tokens.get(i));

					if (inFNDef
							|| inConstructor
							|| ((i > 0 && tokens.get(i - 1).getString()
									.equals("const")) || (i > 1 && tokens
									.get(i - 2).getString().equals("catch"))))
						str += varName + ":" + varType; // const str:String
					else
						str += "var " + varName + ":" + varType;

					i += 1;
					used = true;
				} else if (isIdentifier(tokens.get(i))
						&& tokens.get(i + 1).getType() == Token.STRING_LITERAL
						&& tokens.get(i + 2).toString().equals("(")) { // Function
																		// definition
					inFNDef = true;
					cFNName = tokens.get(i + 1).toString();
					cFNType = toASType(tokens.get(i));

					str += "function " + cFNName;
					used = true;
					i += 1;
				}
			}

			if (tokens.get(i).toString().equals("class")
					|| tokens.get(i).toString().equals("interface")) {
				if (isInnerClass) {

					if (!post.equals("")) {
						int closeBracketIndex = str.lastIndexOf("}");
						if (closeBracketIndex != -1) {

							str = str.substring(0, closeBracketIndex + 1)
									+ post
									+ str.substring(closeBracketIndex + 1,
											str.length() + 1);
						}
						post = "";
					}
					int startPos = str.length() - 1;
					posInnerClass.add(startPos);
				}

				if (i > 0 && !tokens.get(i - 1).getString().equals("public")) {
					str += "\n" + "internal ";
				}

				isJavaFile = true;
				classCount++;
				isInnerClass = true;
			}

			if (i < tokens.size() - 3) { // Constructor definition
				if (isPPP(tokens.get(i)) && isIdentifier(tokens.get(i + 1))
						&& tokens.get(i + 2).equals("(")) {
					inConstructor = true;
					used = true;
					str += tokens.get(i) + " function " + tokens.get(i + 1);
					i++;
				}
			}

			if (i < tokens.size() - 3) {
				if (tokens.get(i).toString().equals("package")
						&& tokens.get(i + 1).getType() == Token.STRING_LITERAL
						&& tokens.get(i + 2).getString().equals(";")) {
					str += tokens.get(i) + " " + tokens.get(i + 1) + " {\n";
					used = true;
					i += 2;
					post += "\n}";
				}
			}

			if (i < tokens.size() - 3) {
				if (tokens.get(i).toString().equals("(")
						&& isIdentifier(tokens.get(i + 1))
						&& tokens.get(i + 2).equals(")")) {
					if (!tokens.get(i - 1).getType()
							.equals(Token.STRING_LITERAL)
							&& (tokens.get(i - 1).getString().equals("return") || !tokens
									.get(i - 1).getType().equals(Token.KEYWORD))) {
						String castType = tokens.get(i + 1).toString();
						i += 3;
						String n;
						int inside = 0;
						String sss;
						int start = i;
						sss = "";
						while (true) {
							n = tokens.get(i).toString();
							if (n.equals("(") || n.equals("[") || n.equals("{")) {
								inside++;
								sss += " " + n;
							}

							if (inside > 0) {
								if (n.equals(")") || n.equals("]")
										|| n.equals("}")) {
									if (inside > 0)
										inside--;
									sss += n;
								}
							} else {
								if (tokens.get(i).getType() == Token.SYMBOL
										&& !n.equals(".")) {
									i--;
									break;
								}
							}
							i++;
						}
						sss = orig.substring(tokens.get(start).getPos(), tokens
								.get(i + 1).getPos());
						str += castType + "(" + sss + ")";
						used = true;
					}
				}
			}

			if (i < tokens.size() - 5) {
				if (isIdentifier(tokens.get(i))
						&& tokens.get(i + 1).toString().equals("[")
						&& tokens.get(i + 2).equals("]")
						&& tokens.get(i + 3).getType() == Token.STRING_LITERAL
						&& (tokens.get(i + 4).getString().equals("=")
								|| tokens.get(i + 4).getString().equals(";")
								|| tokens.get(i + 4).getString().equals(",") || tokens
								.get(i + 4).equals(")"))) { // array
					String varName = tokens.get(i + 3).toString();
					String varType = "Array";
					if (inFNDef || inConstructor)
						str += varName + ":" + varType;
					else
						str += "var " + varName + ":" + varType;
					i += 3;
					used = true;
				}
			}
			if (t.getString().equals(")")) {
				if (inFNDef) {
					inFNDef = false;
					used = true;
					str += "):" + cFNType + " ";
				} else if (inConstructor) {
					inConstructor = false;
				}
			}
			if (t.getType() == Token.NUMBER) { // clean it up
				str += cleanNumber(t.getString());
				used = true;
			}
			if (t.getType() == Token.COMMENT) {
				// used = true
			}
			t = tokens.get(i);
			newPos = t.getPos() + t.getString().length();
			if (i < tokens.size() - 1)
				newPos = tokens.get(i + 1).getPos();

			if (t.getString().equals("@")) { // && (tokens.get(i + 1) as
												// Token).getString() ==
												// 'override'

				used = true;
				if (tokens.get(i + 1).toString().equals("Override")) {
					str += "\r\n"
							+ (tokens.get(i + 1)).getString().toLowerCase()
							+ " ";

				} else {
					for (String key : packageImports.keySet()) {
						if (key == tokens.get(i + 1).getString()) {

							str = str.replace(packageImports.get(key) + "\n",
									"");
						}
					}
				}
				if (tokens.get(i + 2).toString().equals("(")) {
					while (!tokens.get(i).toString().equals(")")) {
						i++;
						if (i == tokens.size()) {
							return null;
						}
					}
					i--;
				}

				i++;
				newPos = tokens.get(i + 1).getPos();
			}
			int index = t.getString().indexOf("equals");

			if ((index >= 0) && (index + 6 == t.getString().length())) {
				if (index == 0) {
					str = str.substring(0, str.length() - 1);
					str = removeExclamationPoint(str, true);
					str += " == ";
					used = true;
				} else {
					str = removeExclamationPoint(str, false);
					index = orig.indexOf("equals", t.getPos());
					temp = orig.substring(t.getPos(), index - 1);// + ' == ';
					if (hasBeenAddedExclamationPoint) {
						temp += " != ";
						hasBeenAddedExclamationPoint = false;
					} else {
						temp += " == ";
					}

					str += temp;
					used = true;
				}
			}

			if (!used) {
				if (str.indexOf("...", str.length() - 4) != -1
						&& ((i > 5) && (tokens.get(i - 5).getString()
								.equals("(") || tokens.get(i - 5).getString()
								.equals(",")))) {

					int indexOpeningBracket = str.lastIndexOf("(");
					int char1 = str.indexOf(",", indexOpeningBracket);

					while (char1 != -1) {
						if (indexOpeningBracket < char1)
							indexOpeningBracket = char1;

						char1 = str.indexOf(",", char1 + 1);
					}

					str = str.substring(0, indexOpeningBracket + 1);
					str += " ... " + t.getString();

				} else if (t.getString().equals("throws")) {
					i++;
					newPos = tokens.get(i + 1).getPos();
				} else if (t.getString().equals("instanceof")) {
					str += "is ";
				} else if (t.getString().equals("final")) {
					if (((tokens.get(i - 1)).getString().equals("static"))
							&& ((tokens.get(i + 3)).getString().equals("="))) {
						str += "const ";
						tokens.get(i).setString("const");
					}
				} else {
					temp = orig.substring(lastPos, newPos);
					str += temp;
				}
			}
			lastPos = newPos;
		}
		if (isJavaFile) {
			String[] lines = orginalStr.split("\n");
			lineCount = lines.length;
			if (lines[lineCount - 1].length() == 0)
				lineCount--;
		}
		return addImportInnerClasses(str + post);
	}

	private String addImportInnerClasses(String str) {
		String code = str;
		if (posInnerClass.size() > 0) {
			int index = str.lastIndexOf("}", posInnerClass.get(0));
			if (index != -1) {
				code = "";
				posInnerClass.add(str.length() - 1);
				String classCode = str.substring(0, index + 1);
				for (int i = 0; i < posInnerClass.size() - 1; i++) {
					int beginIndex = str.lastIndexOf("}", posInnerClass.get(i));
					int endIndex = str.lastIndexOf("}",
							posInnerClass.get(i + 1));

					String innerclassCode = str.substring(beginIndex + 1,
							endIndex + 1);
					String imports = "\n\n";

					for (String key : packageImports.keySet()) {
						if (!innerclassCode.matches(key)) {
							imports += packageImports.get(key) + "\n";
						}
					}

					code += imports + innerclassCode;

				}
				code = classCode + code;

				while (code.matches("\n\n\n"))
					code = code.replace("\n\n\n", "\n\n");
			}
		}
		return code;
	}

	private String removeExclamationPoint(String str, boolean isSearchQuote) {
		int indexOpeningBracket = str.lastIndexOf("(");

		int char1 = str.indexOf("&", indexOpeningBracket);

		if (indexOpeningBracket < char1)
			indexOpeningBracket = char1;

		char1 = str.indexOf("|", indexOpeningBracket);

		if (indexOpeningBracket < char1)
			indexOpeningBracket = char1;

		int indexExclamationPoint = str.indexOf("!", indexOpeningBracket);
		String temp = "";
		if (indexExclamationPoint == -1) {
			temp = new String(str);
		} else if (isSearchQuote) {
			if ((str.indexOf("\"") != -1)
					&& (str.indexOf("\"") != str.lastIndexOf("\""))) {
				temp = str.substring(0, indexExclamationPoint);
				temp += str.substring(indexExclamationPoint + 1, str.length());
			} else {

			}
		} else {
			if (indexExclamationPoint == str.length() - 1) {
				temp = str.substring(0, indexExclamationPoint);
				hasBeenAddedExclamationPoint = true;
			} else {
				temp = new String(str);
			}
		}
		return temp;
	}

	private boolean isIdentifier(Token token) {
		return isPrimitiveType(token.getString())
				|| token.getType() == Token.STRING_LITERAL;
	}

	private boolean isPrimitiveType(String str) {
		return str.equals("int") || str.equals("byte") || str.equals("double")
				|| str.equals("boolean") || str.equals("float")
				|| str.equals("void") || str.equals("char")
				|| str.equals("short") || str.equals("long");
	}

	private boolean isPPP(Token token) {
		String str = token.toString();
		return str.equals("public") || str.equals("private")
				|| str.equals("protected");
	}

	private String toASType(Token token) {
		String tokenString = token.getString();

		if (tokenString.equals("double") || tokenString.equals("float"))
			return "Number";
		if (tokenString.equals("Integer"))
			return "int";
		if (tokenString.equals("boolean"))
			return "boolean";
		if (tokenString.equals("byte"))
			return "uint";
		if (tokenString.equals("long") || tokenString.equals("short"))
			return "Number";
		if (tokenString.equals("char"))
			return "String";
		return tokenString;
	}

	private String cleanNumber(String str) {
		while (str.matches("f"))
			str = str.replace("f", "");
		return str;
	}
}
